package org.tigris.juxy; import org.tigris.juxy.builder.JuxyParams; import org.tigris.juxy.builder.TemplatesBuilder; import org.tigris.juxy.builder.TemplatesBuilderImpl; import org.tigris.juxy.util.ArgumentAssert; import org.tigris.juxy.util.DOMUtil; import org.tigris.juxy.xpath.XPathExpr; import org.w3c.dom.Document; import org.w3c.dom.DocumentFragment; import org.w3c.dom.Node; import javax.xml.transform.*; import javax.xml.transform.dom.DOMResult; import javax.xml.transform.sax.SAXSource; import java.util.Iterator; import java.util.Map; /** * $Id: RunnerImpl.java,v 1.15 2006-11-09 18:59:07 pavelsher Exp $ * <p/> * This runner uses only standard features. It does not use any XSLT engine-specific extensions. * * @author Pavel Sher */ class RunnerImpl implements Runner { private static TransformerFactory trFactory = null; private TemplatesBuilder templatesBuilder = null; private boolean tracingEnabled = false; protected RunnerImpl() { createTransformerFactory(); templatesBuilder = new TemplatesBuilderImpl(trFactory); checkEnvironment(); } private void checkEnvironment() { if (!trFactory.getFeature(SAXSource.FEATURE)) throw new JuxyRuntimeException("The specified transformer factory does not support SAXSource"); if (!trFactory.getFeature(DOMResult.FEATURE)) throw new JuxyRuntimeException("The specified transformer factory does not support DOMResult"); } private void createTransformerFactory() { trFactory = TransformerFactory.newInstance(); } private Transformer getTransformer() throws TransformerConfigurationException { Templates templates = templatesBuilder.build(); if (templates == null) throw new JuxyRuntimeException("Failed to create transformer, check Juxy logs for details"); return templates.newTransformer(); } public RunnerContext newRunnerContext(String systemId) { ArgumentAssert.notEmpty(systemId, "System id must not be empty"); return new RunnerContextImpl(systemId); } public RunnerContext newRunnerContext(String systemId, URIResolver resolver) { ArgumentAssert.notEmpty(systemId, "System id must not be empty"); ArgumentAssert.notNull(resolver, "Resolver must not be null"); return new RunnerContextImpl(systemId, resolver); } public Node callTemplate(RunnerContext ctx, String name) throws TransformerException { ArgumentAssert.notNull(ctx, "RunnerContext must not be null"); ArgumentAssert.notEmpty(name, "Template name must not be empty"); RunnerContextImpl sctx = getContext(ctx); setupTemplatesBuilder(sctx); templatesBuilder.setInvokationStatementInfo(name, sctx.getTemplateParams()); return transformSource(sctx.getSourceDocument(), sctx); } public Node applyTemplates(RunnerContext ctx) throws TransformerException { ArgumentAssert.notNull(ctx, "RunnerContext must not be null"); return internalApplyTemplates(ctx, null, null); } public Node applyTemplates(RunnerContext ctx, XPathExpr selectXpathExpr) throws TransformerException { ArgumentAssert.notNull(ctx, "RunnerContext must not be null"); ArgumentAssert.notNull(selectXpathExpr, "XPath expression must not be null"); return internalApplyTemplates(ctx, selectXpathExpr, null); } public Node applyTemplates(RunnerContext ctx, XPathExpr selectXpathExpr, String mode) throws TransformerException { ArgumentAssert.notNull(ctx, "RunnerContext must not be null"); ArgumentAssert.notNull(selectXpathExpr, "XPath expression must not be null"); ArgumentAssert.notEmpty(mode, "Mode must not be empty"); return internalApplyTemplates(ctx, selectXpathExpr, mode); } public void enableTracing() { tracingEnabled = true; } public void disableTracing() { tracingEnabled = false; } private Node internalApplyTemplates(RunnerContext ctx, XPathExpr selectXpathExpr, String mode) throws TransformerException { RunnerContextImpl sctx = getContext(ctx); setupTemplatesBuilder(sctx); templatesBuilder.setInvokationStatementInfo(selectXpathExpr, mode, sctx.getTemplateParams()); return transformSource(sctx.getSourceDocument(), sctx); } private RunnerContextImpl getContext(RunnerContext ctx) { ArgumentAssert.notNull(ctx, "Runner context must not be null"); RunnerContextImpl st_ctx = (RunnerContextImpl) ctx; st_ctx.checkComplete(); return st_ctx; } private void setupTemplatesBuilder(RunnerContextImpl ctx) { templatesBuilder.setImportSystemId(ctx.getSystemId(), ctx.getResolver()); templatesBuilder.setTracingEnabled(isTracingEnabled()); templatesBuilder.setCurrentNode(ctx.getCurrentNodeSelector()); templatesBuilder.setGlobalVariables(ctx.getGlobalVariables()); templatesBuilder.setNamespaces(ctx.getNamespaces()); } public boolean isTracingEnabled() { String propertyValue = System.getProperty(JuxyProperties.XSLT_TRACING_PROPERTY); if ("on".equals(propertyValue)) return true; if ("off".equals(propertyValue)) return false; return tracingEnabled; } private Node transformSource(Source sourceDoc, RunnerContextImpl ctx) throws TransformerException { Transformer transformer = getTransformer(); transformer.setOutputProperty(OutputKeys.METHOD, "xml"); if (ctx.getGlobalParams() != null) { Map namespaces = ctx.getNamespaces(); Iterator it = ctx.getGlobalParams().iterator(); while (it.hasNext()) { GlobalParam param = (GlobalParam) it.next(); transformer.setParameter(param.getTransformerQName(namespaces), param.getValue()); } if (isTracingEnabled()) { Tracer.startTracing(System.out); } } Document document; DocumentFragment fragment; try { document = DOMUtil.newDocument(); fragment = document.createDocumentFragment(); document.appendChild(fragment); DOMResult result = new DOMResult(fragment); transformer.transform(sourceDoc, result); fragment.normalize(); } finally { if (isTracingEnabled()) { Tracer.stopTracing(); } } DOMUtil.logDocument("Transformation result:", fragment); return (Document) ResultDocumentProxy.newInstance(document, fragment); } }